Redis RDB和AOF持久化和数据恢复方式以及DB常用指令

RDB 快照持久化方式

RDB(Redis Database)在指定的时间间隔内,将内存中的全量数据生成一个二进制快照文件(dump.rdb)。类似于“拍照片”。核心配置参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 触发机制:save <秒> <修改次数>
# 触发频率:不要设置得太频繁,防止 fork 消耗 CPU。
# 建议只保留这三行,甚至可以根据业务减少。
save 3600 1 # 1小时改1个key
save 300 100 # 5分钟改100个key
save 60 10000 # 1分钟改1万个key

dbfilename dump.rdb # 文件名
dir /var/lib/redis # 存储目录
rdbcompression yes # 开启 LZO 压缩,虽然耗点 CPU,但能显著减小 RDB 体积
rdbchecksum yes # 开启 RDB 校验,确保文件没损坏,增加恢复可靠性
stop-writes-on-bgsave-error yes # 备份失败时,禁止写入(预警机制,建议开启)

# 内存级保护
maxmemory 3gb # 务必设置。建议设为物理内存的 60%-70%。剩下的 30% 留给 BGSAVE 时的 fork 操作和操作系统的页缓存。
maxmemory-policy # 建议设置为 volatile-lru 或 allkeys-lru


# 内核级保护
# 允许内核在 fork 时不进行保守估计。
vi /etc/sysctl.conf
vm.overcommit_memory = 1
sysctl -p

优点:恢复大数据集速度极快;文件紧凑,适合异地备份。

缺点:数据丢失风险大(上次备份到宕机之间的数据会丢失);fork 子进程时在大内存环境下可能导致瞬时卡顿。


AOF 追加日志持久化方式

AOF (Append Only File):记录每一个写操作指令,以追加的方式写入文件(appendonly.aof)。类似于“记账本”。核心配置参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
appendonly yes                   # 开启 AOF
appendfilename "appendonly.aof"

# 同步策略(核心)
appendfsync everysec # 每秒同步一次(性能与安全的最优折中)
# appendfsync always # 每次写入都同步(安全但慢)
# appendfsync no # 交给操作系统决定(最快但不安全)

# AOF 重写配置(防止文件无限变大)
# 重写(Rewrite)触发机制:
# 当 AOF 文件大小比上次重写后增长了 100% 且 达到 1GB 时触发。
# 调大 min-size 可以减少频繁重写带来的 IO 抖动。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 1gb

# 【关键】在重写执行期间,是否禁止 fsync 刷盘?
# 设置为 no 最安全,但在磁盘 IO 极高时可能会导致主线程阻塞。
# 如果你使用 SSD,建议设为 no。
no-appendfsync-on-rewrite no

# 开启混合持久化(Redis 7 默认开启,头部为 RDB 格式)
aof-use-rdb-preamble yes

优点:数据最安全(最多丢失1秒数据);日志可读,可以手动修复(如误删后删掉 AOF 末尾的 FLUSHALL 指令)。

缺点:文件体积比 RDB 大;数据恢复速度慢(需要逐条回放指令)。


生产环境最佳实践

建议采用 “混合持久化” 策略:

  • 策略:RDB + AOF 同时开启

    • 混合模式:在 redis.conf 中设置 aof-use-rdb-preamble yes。AOF 重写时,文件前半部分是 RDB 格式(加载快),后半部分是增量指令(数据全)。

    • 异地备份:每天定时通过 cron 脚本将 dump.rdb 拷贝到另一台服务器或云存储,防止物理机房故障。

    • 针对向量搜索(Valkey-Search)的优化:降低 AOF 重写频率:向量索引数据很大,频繁重写会造成磁盘 IO 飙升。建议将 auto-aof-rewrite-min-size (默认64mb)调大(如 512mb 或 1gb)。

    • 硬件级保障

      • 使用 SSD:Redis 持久化非常依赖磁盘的随机写入性能,SSD 是必须的。
      • 预留内存:Linux 在 fork 时需要一定的内存余量。建议系统内存占用不要超过 70%,并设置 vm.overcommit_memory = 1
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      # 在配置 Redis 持久化(尤其是 BGSAVE)时,vm.overcommit_memory = 1 是 Linux 内核参数中
      # 最核心的一个。如果不设置它,在高负载下你的 Redis 经常会因为“内存不足”而备份失败,甚至崩溃。
      # 简单来说,它是 Linux 处理内存分配的一种策略。
      ## 默认状态 (0):当 Redis 请求内存(比如 fork 子进程做快照)时,内核会进行启发式估算。如果它认为内存可能不够,就会拒绝该请求。
      ## 激进状态 (1):内核总是允许内存分配请求,直到物理内存真的用完。
      ## 设置成 1 后,内核会相信 Redis,直接允许 fork,从而保证持久化任务顺利开启。

      # 临时生效(立即生效,重启失效)
      echo 1 > /proc/sys/vm/overcommit_memory
      # 或者
      sysctl -w vm.overcommit_memory=1

      # 永久生效(推荐)
      vi /etc/sysctl.conf
      # 在文件末尾添加一行
      vm.overcommit_memory = 1
      # 加载配置使其生效
      sysctl -p


      ## 关闭linux内存大页
      echo never > /sys/kernel/mm/transparent_hugepage/enabled
      echo never > /sys/kernel/mm/transparent_hugepage/defrag


      # 确保 net.core.somaxconn 至少设为 2048,匹配 Redis 的高并发需求。
      net.core.somaxconn = 2048


误操作后怎么快速恢复!

比如执行了 FLUSHALL 后能否恢复数据,取决于你的 持久化配置(AOF 或 RDB)以及你反应的速度。请立即按照以下步骤进行“抢救”:

  • 第一步:保持冷静,立即阻止任何新的写入:一旦发现误操作,不要重启 Redis(除非你没开 AOF),因为重启可能会触发新的持久化操作,覆盖掉现有的备份文件。

  • 第二步:根据持久化方式选择恢复方案

    • 场景 A:你开启了 AOF(最稳妥的恢复方式)

      • 由于 AOF 记录的是每一条写命令,FLUSHALL 也会作为一个命令记在日志文件的末尾。你只需要把这一条删掉即可。

      • 立即备份 AOF 文件:防止后续操作失误。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        # 如果是单纯的aof方式:
        cp appendonly.aof appendonly.aof.bak

        # 如果是混合rdb+aof方式:你会看到类似的至少三个文件:
        # appendonly.aof.2.base.rdb:基础文件,这是混合持久化的核心,是上一次AOF重写时的内存全量快照(RDB格式)。
        # appendonly.aof.2.incr.aof:增量文件,它记录了从上一次生成 .base.rdb 之后的所有写命令。你的 FLUSHALL 命令就写在这个文件的末尾。
        # appendonly.aof.manifest:清单文件,告诉 Redis:当前的 AOF 由哪个 Base 文件和哪些 Incr 文件组成,以及它们的序列号(这里是 2),Redis 启动时会先读它。
        mkdir /root/redis_backup
        cp appendonly.aof.* /root/redis_backup/
      • 打开 AOF 文件进行编辑:

        1
        2
        3
        vim appendonly.aof   或者   vim appendonly.aof.2.incr.aof
        # 删除末尾的 FLUSHALL 命令:
        # 滚动到文件最底部,你会看到类似 *1\r\n$8\r\nFLUSHALL 这样的记录。将其彻底删除。
      • 重启 Redis 实例: Redis 会重新读取修改后的 AOF 文件,数据就会像 “录像回放”一样全部回来(除了那条被你删掉的清空命令)。

    • 场景 B:你只开启了 RDB:这种情况比较看运气,取决于 FLUSHALL 之后是否触发了新的 RDB 备份。

      • 检查 dump.rdb 文件的时间戳: 如果 dump.rdb 的最后修改时间是在你执行 FLUSHALL 之前,那么你非常幸运。立即备份 dump.rdb 文件。

      • 立即强制关闭 Redis 进程(不要执行正常的 shutdown,因为正常关机会尝试保存当前内存状态,即清空后的状态):

        1
        2
        3
        # 千万不要执行 redis-cli shutdown,因为正常退出可能再次触发持久化。
        ps -ef | grep redis
        kill -9 [Redis的PID]
      • 把备份的 dump.rdb 拷贝回数据目录。

      • 重启 Redis,数据会恢复到上一次快照时的状态。

    • 场景 C:你开启了混合持久化(AOF 头部是 RDB)

      • 操作逻辑同 场景 A。依然是编辑 appendonly.aof,找到末尾的文本部分(AOF 混合模式下,文件末尾通常是正常的 AOF 文本指令),删掉 FLUSHALL 即可。
  • 第三步:最后的 “核武器”——冷备份:如果你之前按照我建议的生产环境最佳实践,做了异地备份(比如每天凌晨拷贝一次 dump.rdb 到另一台机器),那么你可以拿昨天的备份文件进行恢复。虽然会丢失今天的数据,但总好过全量丢失。

  • 最后:为了防止你的redis数据再次遭遇这种 “灭顶之灾”,请务必执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 重命名命令(最有效): 在 redis.conf 中加入:
    rename-command FLUSHALL "OWLIAS_DANGEROUS_CLEAN_ALL"
    rename-command FLUSHDB "" # 彻底禁用
    rename-command CONFIG "OWLIAS_ADMIN_CONFIG"

    # 权限控制: 确保生产环境的 Redis 开启了 requirepass 密码认证,避免脚本或外部工具误触。

    # 开启 AOF
    # 正如你看到的,AOF 是唯一能让你“反悔” 的后悔药。


异地定时备份脚本

第一步:

$ vim /root/scripts/redis_backup.sh

$ chmod +x /root/scripts/redis_backup.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/bin/bash

# --- 配置信息 ---
REDIS_CLI="/usr/local/bin/redis-cli"
export REDISCLI_AUTH="你的密码" # 如果没有密码留空,Redis 客户端支持读取 REDISCLI_AUTH 环境变量,这样你就不用在命令行参数里传密码了。
DATA_DIR="/var/lib/redis" # Redis数据目录
BACKUP_DIR="/data/redis_backups" # 本地备份存放临时目录
REMOTE_SERVER="user@remote_ip" # 远程服务器账号及IP
REMOTE_DIR="/backup/owlias_redis/" # 远程服务器存放路径
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/redis_backup.log"

# --- 创建备份目录 ---
mkdir -p $BACKUP_DIR

echo "[$DATE] 开始执行备份..." >> $LOG_FILE

# 1. 触发 BGSAVE 生成最新的快照
#
echo "触发 BGSAVE..." >> $LOG_FILE
$REDIS_CLI BGSAVE

# 2. 等待备份完成(根据数据量调整等待时间,或循环检查 INFO Persistence)
sleep 10

# 3. 打包当前所有的持久化文件 (Base RDB, Incr AOF, Manifest)
# Redis 7 的 Multi-Part AOF 建议全部打包
tar -czf $BACKUP_DIR/redis_data_$DATE.tar.gz -C $DATA_DIR .

# 4. 将备份文件传输到异地服务器 (建议配置 SSH 免密登录)
ssh $REMOTE_SERVER "mkdir -p $REMOTE_DIR"
if [ $? -eq 0 ]; then
echo "远程目录就绪,开始传输..." >> $LOG_FILE
scp $BACKUP_DIR/redis_data_$DATE.tar.gz $REMOTE_SERVER:$REMOTE_DIR
if [ $? -eq 0 ]; then
echo "传输成功。" >> $LOG_FILE
else
echo "错误:文件传输失败!" >> $LOG_FILE
fi
else
echo "错误:无法在远程服务器创建目录!" >> $LOG_FILE
fi

# 5. 清理本地过旧的备份(保留最近 7 天)
find $BACKUP_DIR -mtime +7 -name "*.tar.gz" -exec rm -rf {} \;

echo "[$DATE] 备份任务完成。" >> $LOG_FILE


第二步:配置 SSH 免密登录(核心)

  • 在 Redis 服务器运行:ssh-keygen -t rsa(一路回车)。

  • 拷贝公钥到备份服务器:ssh-copy-id user@remote_ip


第三步:设置定时任务 (Crontab)

执行 crontab -e,添加以下行,设置为每天凌晨 3:00 运行:

1
00 03 * * * /bin/bash /root/scripts/redis_backup.sh >> /var/log/redis_backup_cron.log 2>&1


DB相关的常用指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
## 数据库切换与基础管理
# 查看当前有多少库
> config get databases
# 切换到指定的数据库
> select 2
# 返回当前数据库中 Key 的总数
> dbsize
# 从当前数据库中随机返回一个 Key
> randomkey
# 清空当前节点上的选择的数据库(在master节点执行,慎用!)
> flushdb
# 清空当前节点上的所有的库(在master节点执行,极度危险!)
> flushall
# 查看哪些库里已经存了东西,以及每个库有多少 Key
> info keyspace
# Keyspace
db0:keys=2,expires=0,avg_ttl=0,subexpiry=0
db2:keys=1,expires=1,avg_ttl=299721,subexpiry=0


## DB 内的操作
# 判断键是否存在
> exists user:1
# 查看当前库中匹配的key有哪些
> keys user*
# 键改名
> rename u user:1
# 将当前库的k-v移到另一个库
> move user:1 2
# 查看 Key 的数据类型
> type user:1


## DB信息监控
> info
# 查看持久化详情(最后一次落盘是否成功)
> info persistence
# 查看内存占用(是否达到了你设定的 maxmemory)
> info memory
# 查看当前有多少客户端连接
> info clients
# 实时打印出 Redis 服务器接收到的所有命令(生产环境慎用,高并发下会严重影响性能)
> monitor


## 数据持久化
# 同步保存当前节点的所有库的数据到磁盘(dump.rdb),阻塞式:会卡住当前集群节点的所有请求,直到保存完成
> save
# 在后台异步保存当前节点的所有库的数据(dump.rdb),非阻塞:Redis 会 fork 一个子进程进行保存。
> bgsave
# 返回最近一次成功保存的时间戳
> lastsave
# 手动触发 AOF 日志重写,减小 appendonly.aof 文件体积(对性能影响中等)
bgrewriteaof

[注意]:

  • Redis 集群模式下不支持多数据库,只能使用 DB 0,因此在集群环境下执行 save/bgsave/bgrewriteaof 等指令,本质上就是针对该节点唯一的 DB 0 进行持久化。
  • 自动化胜过手动:在你的 redis.conf 中配置 save 规则(如 save 900 1)或开启 appendonly yes。Redis 会自动在后台调用 BGSAVE 或重写 AOF,不需要你手动执行。
  • 如果你以后将应用部署到集群环境,备份时需要编写脚本,循环登录到每一个 Master 节点去执行 BGSAVE,并把每个节点的 dump.rdb 都拷贝出来。
  • 除非是在停机维护或极端紧急情况下,否则永远不要在生产环境执行 SAVE。